﻿using System;

namespace StockModel
{
	internal class QuotationDailyStatisticsCalculator : IDisposable
	{
		#region Attributes

		private readonly DailyKeyQuotations _dailyKeyQuotations;
		private Quotation _previousLastOperation;

		#endregion

		#region Properties

		public QuotationDailyStatistics Statistics { get; private set; }

		#endregion

		#region Public Methods

		public QuotationDailyStatisticsCalculator(DailyKeyQuotations dailyKeyQuotations)
		{
			_dailyKeyQuotations = dailyKeyQuotations;
			_dailyKeyQuotations.PropertyChanged += DailyInfo_PropertyChanged; // Disposed

			this.Statistics = new QuotationDailyStatistics();
		}

		#endregion

		#region Event Handlers

		private void DailyInfo_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "LastQuotation")
			{
				this.Statistics.GapDifferencePercentage = (_dailyKeyQuotations.LastQuotation.Sellers[0].Value - _dailyKeyQuotations.LastQuotation.Buyers[0].Value) / _dailyKeyQuotations.LastQuotation.Value * 100;
				this.Statistics.BidAskAverage = (_dailyKeyQuotations.LastQuotation.Sellers[0].Value + _dailyKeyQuotations.LastQuotation.Buyers[0].Value) / 2;

				if (_dailyKeyQuotations.Opening != null)
				{
					this.CalculateOpeningDifference();
				}

				if (_dailyKeyQuotations.PreviousClosing != null)
				{
					this.CalculatePreviousDifference();
				}

				if (_dailyKeyQuotations.LastOperation != null)
				{
					this.Statistics.LastOperation = _dailyKeyQuotations.LastQuotation.Date - _dailyKeyQuotations.LastOperation.Date;
				}
			}
			else if (e.PropertyName == "LastOperation")
			{
				if (_dailyKeyQuotations.LastOperation == null)
				{
					this.Statistics.LastOperation = null;
					this.Statistics.LastVolume = null;
					_previousLastOperation = null;
				}
				else
				{
					this.Statistics.LastVolume = _previousLastOperation == null ? _dailyKeyQuotations.LastOperation.Volume : _dailyKeyQuotations.LastOperation.Volume - _previousLastOperation.Volume;
					_previousLastOperation = _dailyKeyQuotations.LastOperation;
				}
			}
			else if (e.PropertyName == "Max")
			{
				if (_dailyKeyQuotations.Max == null)
				{
					this.Statistics.MaxOpenDifferencePercentage = null;
				}
				else if (_dailyKeyQuotations.Opening != null)
				{
					this.Statistics.MaxOpenDifferencePercentage = (_dailyKeyQuotations.Max.Value - _dailyKeyQuotations.Opening.Value) / _dailyKeyQuotations.Opening.Value * 100;
				}
			}
			else if (e.PropertyName == "Min")
			{
				if (_dailyKeyQuotations.Min == null)
				{
					this.Statistics.MinOpenDifferencePercentage = null;
				}
				else if (_dailyKeyQuotations.Opening != null)
				{
					this.Statistics.MinOpenDifferencePercentage = (_dailyKeyQuotations.Min.Value - _dailyKeyQuotations.Opening.Value) / _dailyKeyQuotations.Opening.Value * 100;
				}
			}
			else if (e.PropertyName == "Opening")
			{
				if (_dailyKeyQuotations.Opening == null)
				{
					this.Statistics.OpenDiffPercentage = null;
				}
				else if (_dailyKeyQuotations.LastQuotation != null)
				{
					this.CalculateOpeningDifference();
				}
			}
			else if (e.PropertyName == "PreviousClosing")
			{
				if (_dailyKeyQuotations.PreviousClosing == null)
				{
					this.Statistics.PreviousDayDiffPercentage = null;
				}
				else if (_dailyKeyQuotations.LastQuotation != null)
				{
					this.CalculatePreviousDifference();
				} 
			}
		}

		#endregion

		#region Private Methods

		private void CalculateOpeningDifference()
		{
			this.Statistics.OpenDiffPercentage = (_dailyKeyQuotations.LastQuotation.Value - _dailyKeyQuotations.Opening.Value) / _dailyKeyQuotations.Opening.Value * 100;
		}

		private void CalculatePreviousDifference()
		{
			this.Statistics.PreviousDayDiffPercentage = (_dailyKeyQuotations.LastQuotation.Value - _dailyKeyQuotations.PreviousClosing.Value) / _dailyKeyQuotations.PreviousClosing.Value * 100;
		}
		
		#endregion

		#region IDisposable

		protected bool Disposed { get; private set; }

		private void Dispose(bool disposing)
		{
			if (!this.Disposed)
			{
				this.InternalDispose(disposing);
			}

			this.Disposed = true;
		}

		protected virtual void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				_dailyKeyQuotations.PropertyChanged -= DailyInfo_PropertyChanged;
			}

			// Dispose here only unmanaged objects 
			// Don’t use managed objects here because maybe 
			// they have been finalized already
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		~QuotationDailyStatisticsCalculator()
		{
			this.Dispose(false);
		}

		#endregion
	}
}
